package org.activityinfo.ui.client.component.form.field.image;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import org.activityinfo.core.shared.util.MimeTypeUtil;
import org.activityinfo.legacy.shared.Log;
import org.activityinfo.model.resource.Resource;
import org.activityinfo.model.resource.ResourceId;
import org.activityinfo.model.resource.Resources;
import org.activityinfo.model.type.image.ImageRowValue;
import org.activityinfo.service.blob.UploadCredentials;
import java.util.List;
import java.util.Map;
/**
* @author yuriyz on 8/12/14.
*/
public class ImageUploadRow extends Composite {
private static final int THUMBNAIL_SIZE = 24;
interface OurUiBinder extends UiBinder<FormPanel, ImageUploadRow> {
}
private static OurUiBinder ourUiBinder = GWT.create(OurUiBinder.class);
private final ImageRowValue value;
private final String fieldId;
private final String resourceId;
private boolean readOnly;
private HandlerRegistration oldHandler;
@UiField
FileUpload fileUpload;
@UiField
HTMLPanel imageContainer;
@UiField
ImageElement loadingImage;
@UiField
Image thumbnail;
@UiField
Button downloadButton;
@UiField
Button removeButton;
@UiField
VerticalPanel formFieldsContainer;
@UiField
Button addButton;
@UiField
FormPanel formPanel;
public ImageUploadRow(ImageRowValue value, String fieldId, String resourceId) {
initWidget(ourUiBinder.createAndBindUi(this));
this.value = value;
this.fieldId = fieldId;
this.resourceId = resourceId;
fileUpload.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
requestUploadUrl();
}
});
downloadButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
download();
}
});
if (value.getBlobId() != null) {
imageContainer.setVisible(false);
downloadButton.setVisible(true);
thumbnail.setVisible(true);
thumbnail.setUrl(buildThumbnailUrl());
}
}
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
fileUpload.setEnabled(!readOnly);
downloadButton.setEnabled(!readOnly);
removeButton.setEnabled(!readOnly);
addButton.setEnabled(!readOnly);
}
private String createUploadUrl() {
String blobId = ResourceId.generateId().asString();
String fileName = fileName();
String mimeType = MimeTypeUtil.mimeTypeFromFileExtension(fileExtension(fileName));
value.setMimeType(mimeType);
value.setFilename(fileName);
value.setBlobId(blobId);
return "/service/blob/credentials/" + blobId;
}
public static String fileExtension(String filename) {
int i = filename.lastIndexOf(".");
if (i != -1) {
return filename.substring(i + 1);
}
return filename;
}
private String fileName() {
final String filename = fileUpload.getFilename();
if (Strings.isNullOrEmpty(filename)) {
return "unknown";
}
int i = filename.lastIndexOf("/");
if (i == -1) {
i = filename.lastIndexOf("\\");
}
if (i != -1 && (i + 1) < filename.length()) {
return filename.substring(i + 1);
}
return filename;
}
private void requestUploadUrl() {
try {
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, URL.encode(createUploadUrl()));
requestBuilder.sendRequest(null, new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
String json = response.getText();
Resource resource = Resources.fromJson(json);
UploadCredentials uploadCredentials = UploadCredentials.fromRecord(resource);
// Remove the old hidden fields before adding the new ones
List<Hidden> hidden = Lists.newArrayListWithCapacity(formFieldsContainer.getWidgetCount());
for (int i = 0; i < formFieldsContainer.getWidgetCount(); i++) {
Widget widget = formFieldsContainer.getWidget(i);
if (widget instanceof Hidden) {
hidden.add((Hidden) widget);
}
}
// We can't just iterate once using the getWidget() method because removing a widget changes indexes
for (Hidden old : hidden) {
formFieldsContainer.remove(old);
}
Map<String, String> formFields = uploadCredentials.getFormFields();
for (Map.Entry<String, String> field : formFields.entrySet()) {
formFieldsContainer.add(new Hidden(field.getKey(), field.getValue()));
}
formPanel.setAction(uploadCredentials.getUrl());
formPanel.setMethod(uploadCredentials.getMethod());
upload();
}
@Override
public void onError(Request request, Throwable exception) {
Log.error("Failed to send request", exception);
}
});
} catch (RequestException e) {
Log.error("Failed to send request", e);
}
}
private void upload() {
imageContainer.setVisible(true);
downloadButton.setVisible(false);
if (oldHandler != null) oldHandler.removeHandler();
oldHandler = formPanel.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
@Override
public void onSubmitComplete(FormPanel.SubmitCompleteEvent event) {
String responseString = event.getResults(); // what about fail results?
imageContainer.setVisible(false);
downloadButton.setVisible(true);
thumbnail.setVisible(true);
thumbnail.setUrl(buildThumbnailUrl());
}
});
formPanel.submit();
}
private void download() {
Window.open(buildImageUrl(), "_blank", null);
}
@Override
public Widget asWidget() {
return this;
}
public ImageRowValue getValue() {
return value;
}
private StringBuilder buildBaseUrl() {
StringBuilder stringBuilder = new StringBuilder("/service/blob/");
stringBuilder.append(resourceId);
stringBuilder.append("/");
stringBuilder.append(fieldId);
stringBuilder.append("/");
stringBuilder.append(value.getBlobId());
return stringBuilder;
}
private String buildThumbnailUrl() {
StringBuilder stringBuilder = buildBaseUrl();
stringBuilder.append("/thumbnail?width=");
stringBuilder.append(THUMBNAIL_SIZE);
stringBuilder.append("&height=");
stringBuilder.append(THUMBNAIL_SIZE);
return stringBuilder.toString();
}
private String buildImageUrl() {
StringBuilder stringBuilder = buildBaseUrl();
stringBuilder.append("/image");
return stringBuilder.toString();
}
}